use std::{
    fmt::{self, Display, Formatter, Result},
    path::{Path, PathBuf},
};

#[derive(Default, Eq, PartialEq, Debug, Copy, Clone)]
pub enum FileType {
    Rust,
    #[default]
    Text,
}

impl Display for FileType {
    fn fmt(&self, formatter: &mut Formatter<'_>) -> Result {
        match self {
            Self::Rust => write!(formatter, "Rust"),
            Self::Text => write!(formatter, "Text"),
        }
    }
}

#[derive(Debug, Default, Eq, PartialEq, Clone)]
pub struct FileInfo {
    file_name: String,
    file_type: FileType,
    path: Option<PathBuf>,
}

impl FileInfo {
    pub fn from(file_name: &str) -> Self {
        let path = PathBuf::from(file_name);

        let file_type = if path
            .extension()
            .map_or(false, |ext| ext.eq_ignore_ascii_case("rs"))
        {
            FileType::Rust
        } else {
            FileType::Text
        };

        FileInfo {
            file_name: file_name.to_string(),
            file_type,
            path: Some(path),
        }
    }

    pub fn get_file_name(&self) -> &str {
        &self.file_name
    }

    pub fn get_path(&self) -> Option<&Path> {
        self.path.as_deref()
    }

    pub const fn has_path(&self) -> bool {
        self.path.is_some()
    }

    pub const fn get_file_type(&self) -> FileType {
        self.file_type
    }
}

impl Display for FileInfo {
    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> fmt::Result {
        let name = self
            .get_path()
            .and_then(|path| path.file_name())
            .and_then(|name| name.to_str())
            .unwrap_or("[No file]");
        write!(formatter, "{name}")
    }
}
